package com.emeraldparser.util;

import com.emeraldparser.util.Graph.Edge;
import com.google.common.base.Objects;

/**
 * 
 * 
 * @author Adam Paynter
 *
 * @param <V>
 * @param <E>
 */
public final class DirectedGraphEdge<V, E> extends AbstractGraphEdge<V, E> {

	private final transient int hashCode;

	private DirectedGraphEdge(V source, V destination, E label) {
		super(source, destination, label);
		this.hashCode = Objects.hashCode(source, destination, label, true);
	}

	public static <V, E> DirectedGraphEdge<V, E> create(V source, V destination, E label) {
		return new DirectedGraphEdge<V, E>(source, destination, label);
	}

	@Override
	public boolean isDirected() {
		return true;
	}

	@Override
	public String toString() {
		return getSource() + "->" + getLabel() + "->" + getDestination();
	}

	@Override
	public int hashCode() {
		return hashCode;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		
		if (obj == null) {
			return false;
		}
		
		if (!(obj instanceof Graph.Edge<?, ?>)) {
			return false;
		}
		
		Graph.Edge<?, ?> other = (Graph.Edge<?, ?>) obj;
		
		if (!other.isDirected()) {
			return false;
		}
		
		return Objects.equal(getSource(), other.getSource())
		    && Objects.equal(getDestination(), other.getDestination())
		    && Objects.equal(getLabel(), other.getLabel());
	}

	@Override
	public boolean comesFrom(V vertex) {
		return Objects.equal(getSource(), vertex);
	}

	@Override
	public boolean goesTo(V vertex) {
		return Objects.equal(getDestination(), vertex);
	}

	@Override
	public boolean isBetween(V source, V destination) {
		return Objects.equal(getSource(), source)
		    && Objects.equal(getDestination(), destination);
	}

	@Override
	public Edge<V, E> invert() {
		return new DirectedGraphEdge<V, E>(getDestination(), getSource(), getLabel());
	}

}
